package crmdna.member;

import static crmdna.common.AssertUtils.ensure;
import static crmdna.common.AssertUtils.ensureEqual;
import static crmdna.common.AssertUtils.ensureNotNull;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.googlecode.objectify.annotation.Cache;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Index;

import crmdna.client.Client;
import crmdna.common.contact.ContactProp;
import crmdna.group.Group;
import crmdna.sequence.Sequence;
import crmdna.sequence.Sequence.SequenceType;

@Entity
@Cache
public class MemberEntity {

	public static class MemberFactory {

		public static MemberEntity create(String client, ContactProp contact,
				long groupId) {

			List<ContactProp> contacts = new ArrayList<>(1);
			contacts.add(contact);

			List<MemberEntity> entities = create(client, contacts, groupId);
			ensureNotNull(entities);
			ensureEqual(1, entities.size());

			return entities.get(0);
		}

		public static List<MemberEntity> create(String client,
				List<ContactProp> contacts, long groupId) {
			final int MAX_MEMBERS = 10000;

			Client.ensureValid(client);
			Group.safeGet(client, groupId);

			ensureNotNull(contacts, "contacts cannot be null");
			
			if (contacts.size() == 0) {
				return new ArrayList<>();
			}

			ensure(contacts.size() <= MAX_MEMBERS,
					"contacts size should be less than or equal to ["
							+ MAX_MEMBERS + "]");

			// no contact can be null
			for (int i = 0; i < contacts.size(); i++) {
				ensureNotNull(contacts.get(i), "contacts.get(" + i
						+ ") is null");
			}

			List<MemberEntity> memberEntities = new ArrayList<>(contacts.size());
			List<Long> memberIds = Sequence.getNext(client,
					SequenceType.MEMBER, contacts.size());

			ensureEqual(contacts.size(), memberIds.size());

			for (int i = 0; i < contacts.size(); i++) {
				MemberEntity memberEntity = new MemberEntity();
				memberEntity.memberId = memberIds.get(i);
				memberEntity.groupIds.add(groupId);

				Member.populateContactDetails(memberEntity,
						contacts.get(i));
				memberEntities.add(memberEntity);
			}

			return memberEntities;
		}
	}

	private MemberEntity() {
	}

	@Id
	long memberId;

	@Index
	String email;

	String firstName;
	String lastName;

	String homeAddress;
	String homeCity;
	String homeState;
	String homeCountry;
	String homePincode;

	String officeAddress;
	String officePincode;

	String homePhone;
	String officePhone;
	@Index
	String mobilePhone;

	@Index
	Set<Long> groupIds = new HashSet<>();

	@Index
	Set<String> qsTags;
	@Index
	Set<Long> programIds = new HashSet<>();

	String listUnverfiedProgramPropJson;

	Map<String, String> customFields;

	int asOfYYYYMMDD; // contact details valid as of this date

	// dependents
	@Index
	String name;
	@Index
	String nameFirstChar;
	@Index
	String firstName3Char;
	@Index
	Set<Long> programTypeIds = new HashSet<>();
	@Index
	Set<Long> practiceIds = new HashSet<>();
	@Index
	Set<String> phoneNumbers = new HashSet<>(); // TODO: remove this

	public MemberProp toProp() {
		MemberProp prop = new MemberProp();
		prop.memberId = memberId;
		prop.contact = new ContactProp();
		prop.contact.email = email;
		prop.contact.firstName = firstName;
		prop.contact.lastName = lastName;
		prop.contact.homeAddress.address = homeAddress;
		prop.contact.officeAddress.address = officeAddress;
		prop.contact.homePhone = homePhone;
		prop.contact.officePhone = officePhone;
		prop.contact.mobilePhone = mobilePhone;
		
		prop.contact.asOfyyyymmdd = asOfYYYYMMDD;

		prop.name = name;
		// prop.qsTags = qsTags;
		prop.groupIds = groupIds;

		prop.programIds = programIds;
		prop.programTypeIds = programTypeIds;
		prop.practiceIds = practiceIds;

		return prop;
	}

	public long getId() {
		return memberId;
	}
}
